var aiutils = require('./aiutils');
var setutils = require('./setUtils');
var DfgRule = require('./DfgRule')
var log4js = require('log4js'),
    logger = log4js.getLogger('DfgAI');

/*
 *
 *   AI for CPU
 *   @function
 *   @param {Array[Cards]} mySolutions: set of solutions
 *   @param {Integer} myLevel: Level of AI
 *
 * */
var PatternAI = [
    {
        nWinningCheck: 0,
        checkLocking: false,
        checkRankPoint: false
    },
    {
        nWinningCheck: 7,
        checkLocking: true,
        checkRankPoint: false
    },
    {
        nWinningCheck: 12,
        checkLocking: false,
        checkRankPoint: true
    }
];
var ncardCheckRankPoint = 8;
var warningLine = 4;
var deadline = 1;
var card_Second = 15;
var card_Thirst = 3;
module.exports.findSolution = function (mySolutions, isLockingHand, myLevel, myCards, cardsTable, otherCards, allSolutions, cardLock) {
    var ret = [];
    var minLenCards = aiutils.minArrayPositive(otherCards.slice(0, otherCards.length - 1))
    var remainCard = fn_remainCard(myCards);
    if (mySolutions.length > 0) {
        // Calculate the number cards on hand
        var lenCards = 0;
        for (var i = 0; i < myCards.length; i++) {
            if (myCards[i].deal == false) {
                lenCards++;
            }
        }
        var myCardsTable = getOtherCardsTable(myCards, cardsTable);
        // Find the winning path depends level
        ret = fn_decided(myCards, cardLock, mySolutions, isLockingHand, remainCard, minLenCards, myCardsTable);
        return ret;
    }
    else{
        ret = [];
        return ret;
    }

}

/*
 *       @function
 *       get other cards Table
 *
 * */
var getOtherCardsTable = function (myCards, cardsTable) {
    // Get the cards on the table of other players
    var cardsT = [];
    for (var i = 3; i < aiutils.Card_Joker; i++) {
        cardsT[i] = [];
        for (var j = 0; j < aiutils.Card_Color.j; j++) {
            cardsT[i][j] = cardsTable[i][j];
        }
    }

    for (var i = 0; i < myCards.length; i++) {
            cardsT[myCards[i].mRank][myCards[i].mColor] = false;
    }
    return cardsT;
}

/*0
 *
 *   @function
 *   check dominant solution
 *  @param: {array[Cards]} solution: Solution to check
 *  @param: {array 2D} cardsTable: Table of other players
 *  @param: {Boolean} isRevolution
 * */
var checkDominantSolution = function (solution, cardsTable, isRevolution) {
    var ret = true;
    if (!aiutils.isEightFlush(solution)) {
        var type = aiutils.typeDealing(solution);
        if (type == aiutils.DealType.Pair) {
            if (!isRevolution) {
                for (var i = solution[0].mRank + 1; i < aiutils.Card_Joker; i++) {
                    var nsame = 0;
                    for (var j = 0; j < aiutils.Card_Color.j; j++) {
                        if (cardsTable[i][j]) {
                            nsame++;
                        }
                    }
                    if (cardsTable[aiutils.Card_Joker]) {
                        nsame++;
                    }
                    if (nsame >= solution.length) {
                        return false;
                    }
                }
            }
            else {
                for (var i = solution[0].mRank - 1; i >= 3; i--) {
                    var nsame = 0;
                    for (var j = 0; j < aiutils.Card_Color.j; j++) {
                        if (cardsTable[i][j]) {
                            nsame++;
                        }
                    }
                    if (cardsTable[aiutils.Card_Joker]) {
                        nsame++;
                    }
                    if (nsame >= solution.length) {
                        return false;
                    }
                }
            }
        }
        else { // Sequence
            if (!isRevolution) {
                for (var i = 0; i < aiutils.Card_Color.j; i++) {
                    var useJoker = !cardsTable[aiutils.Card_Joker];
                    var d = 0;
                    var heap = [];
                    for (var j = solution[0].mRank + solution.length; j < aiutils.Card_Joker; j++) {
                        if (cardsTable[j][i] == true) {
                            d++;
                            //heap.push({mRank: j, mColor: i});
                            if (d >= solution.length) {
                                return false;
                            }
                        }
                        else {
                            if (d > 0 && !useJoker) {
                                d++;
                                useJoker = true;
                                //heap.push({mRank: aiutils.Card_Joker, mColor: aiutils.Card_Color.j});
                                if (d >= solution.length) {
                                    return false;
                                }
                            }
                            else {
                                heap = [];
                                useJoker = !cardsTable[aiutils.Card_Joker];
                                d = 0;
                            }
                        }
                    }
                    if (!useJoker) {
                        d++;
                        //heap.push({mRank: aiutils.Card_Joker, mColor: aiutils.Card_Color.j});
                        if (d >= solution.length) {
                            return false;
                        }
                    }
                }
            }
            else {
                //var heap = [];
                for (var i = 0; i < aiutils.Card_Color.j; i++) {
                    var useJoker = !cardsTable[aiutils.Card_Joker];
                    var d = 0;
                    for (var j = 3; j < solution[0].mRank - solution.length + 1; j++) {
                        if (cardsTable[j][i] == true) {
                            d++;
                            //heap.push({mRank: j, mColor: i});
                            if (d >= solution.length) {
                                return false;
                            }
                        }
                        else {
                            if (d > 0 && !useJoker) {
                                d++;
                                useJoker = true;
                                //heap.push({mRank: aiutils.Card_Joker, mColor: aiutils.Card_Color.j});
                                if (d >= solution.length) {
                                    return false;
                                }
                            }
                            else {
                                useJoker = !cardsTable[aiutils.Card_Joker];
                                d = 0;
                            }
                        }
                    }
                    if (!useJoker) {
                        d++;
                        //heap.push({mRank: aiutils.Card_Joker, mColor: aiutils.Card_Color.j});
                        if (d >= solution.length) {
                            return false;
                        }
                    }
                }
            }
        }
    }
    return ret;
}

/*
 *   @function
 *   Check the winning solutions
 *   checkWinningSolution(solutions, cardsTable, lenCards, isRevolution)
 *   If Exit Solution: Not fail and covering all my cards --> true
 *   Else: for each s on solutions
 *   if (revolution(s)) _isRevolution = !isRevolution
 *   if (not checkDominantSolution(s)){
 *       if (checkWinningSolution(removeRelatedSolution(s, solutions), cardsTable, lenCards - |s|,_isRevolution))
 *           return true
 *   }
 *   return false
 *
 * */
var checkWinningSolution = function (solutions, cardsTable, lenCards, isRevolution) {
    logger.info("checkWinningSolution");
//    logger.info(solutions);
//    logger.info(lenCards);
//    logger.info(isRevolution);
    for (var i = 0; i < solutions.length; i++) {
        //logger.info("Solution ");
        //logger.info(solutions[i]);
        if (solutions[i].length == lenCards && !aiutils.checkFailSolution(solutions[i])) {
            return true;
        }
        //logger.info("is not full");
    }

    for (var i = 0; i < solutions.length; i++) {
        var _isRevolution = aiutils.isRevolution(solutions[i]) ? !isRevolution : isRevolution;
        if (checkDominantSolution(solutions[i], cardsTable, _isRevolution)) {
            var removedSolution = aiutils.removeRelatedSolution(solutions[i], solutions);
            if (checkWinningSolution(removedSolution, cardsTable, lenCards - solutions[i].length, _isRevolution)) {
                return true;
            }
        }
    }

    return false;
}

/*
 *
 *   @function
 *   Calculate the rank point of a set cards
 *   rank_point = number of cards which the ranks less than the current rank's card
 *
 * */
var patRankPoint = function (cards, cardsTable, lenCard, isRevolution) {
    var rankPoint = 0;
    var minLenCards = aiutils.minArrayPositive(lenCard.slice(0, lenCard.length - 1));
    var maxLenCards = aiutils.maxArray(lenCard.slice(0, lenCard.length - 1));

    if (minLenCards < ncardCheckRankPoint || cards.length == lenCard[lenCard.length - 1]) {
        return true;
    }

    var bRet = false;
    var cardCheck = cards.length;
    var iJoker = aiutils.containJoker(cards);
    if (iJoker != null) {
        if (aiutils.typeDealing(cards) == aiutils.DealType.Pair) {
            if (cards.length >= 3) {
                return false;
            }
        }
        else {
            if (cards.length >= 4 && iJoker >= 3) {
                return false;
            }
        }
        cardCheck--;
        rankPoint += aiutils.sumArray(lenCard.slice(0, lenCard.length - 1));
    }
    if (cardCheck >= 1) {
        if (!isRevolution) {
            if (aiutils.typeDealing(cards) == aiutils.DealType.Pair) {
                for (var i = 3; i <= cards[0].mRank; i++) {
                    for (var j = 0; j < aiutils.Card_Color.j; j++) {
                        if (cardsTable[i][j] == true) {
                            rankPoint += cardCheck;
                        }
                    }
                }
            }
            else {
                for (var i = 3; i < cards[0].mRank + cards.length; i++) {
                    if (i - cards[0].mRank >= 1 && i != iJoker) {
                        cardCheck--;
                    }
                    for (var j = 0; j < aiutils.Card_Color.j; j++) {
                        if (cardsTable[i][j] == true) {
                            rankPoint += cardCheck;
                        }
                    }
                }
            }
        }
        else {
            if (aiutils.typeDealing(cards) == aiutils.DealType.Pair) {
                for (var i = aiutils.Card_Joker - 1; i >= cards[0].mRank; i--) {
                    for (var j = 0; j < aiutils.Card_Color.j; j++) {
                        if (cardsTable[i][j] == true) {
                            rankPoint += cardCheck;
                        }
                    }
                }
            }
            else {
                for (var i = cards[0].mRank + cards.length; i < aiutils.Card_Joker; i++) {
                    if (i - cards[0].mRank >= 1 && i != iJoker) {
                        cardCheck--;
                    }
                    for (var j = 0; j < aiutils.Card_Color.j; j++) {
                        if (cardsTable[i][j] == true) {
                            rankPoint += cardCheck;
                        }
                    }
                }
            }
        }
    }

    var sumOCards = aiutils.sumArray(lenCard.slice(0, lenCard.length - 1));
    var sumCards = aiutils.sumArray(lenCard);

    bRet = ((rankPoint / (cards.length * sumOCards)) < (maxLenCards * 2 / sumCards));
    logger.info("patRankPoint");
    logger.info(cards);
    logger.info("rp: " + rankPoint + " sumCard: " + sumCards + " minCard: " + minLenCards + " L : " + (rankPoint / (cards.length * sumCards)) + " R: " + (maxLenCards / sumCards));
    return bRet;
}
var saveCard = function (useSolution, cardsTable, allSolution, cardLock, revolution, othercard) {
    var cardTopRank = [];
    var minLenCards = aiutils.minArrayPositive(othercard.slice(0, othercard.length - 1));

    function check(point, solution) {
        this.point = point;
        this.solution = solution;
    }

    if (cardLock.length > 0) {
        for (var i = 0; i < useSolution.length; i++) {
            cardTopRank.push(new check(0, useSolution[i]));
        }
        for (var j = 0; j < cardTopRank.length; j++) {
            if (aiutils.isLockingHand(cardLock, cardTopRank[j].solution, revolution) == true) {
                cardTopRank[j].point++;
            }
        }
        for (var j = 0; j < cardTopRank.length; j++) {
            if (aiutils.checkJoker(cardTopRank[j].solution) == false && minLenCards > deadline) {
                cardTopRank[j].point -= 4;
            }
        }
        var collectSolution = [];
        for (var i = 0; i < allSolution.length; i++) {
            if (allSolution[i].length > cardLock.length) {
                collectSolution.push(allSolution[i])
            }
        }
        for (var j = 0; j < cardTopRank.length; j++) {
            for (var i = 0; i < collectSolution.length; i++) {
                if (setutils.intersection(cardTopRank[j].solution, collectSolution[i]) == true) {
                    cardTopRank[j].point--;
                }
            }
        }
        var mathRank = 0;
        var number = 0;
        for (var i = 3; i < cardsTable.length; i++) {
            for (var j = 0; j < 3; j++) {
                if (cardsTable[i][j] == true) {
                    mathRank += i;
                    number++;
                }
            }
        }
        var arithmetic_average = mathRank / number;
        if (revolution == false) {
            for (var i = 0; i < cardTopRank.length; i++) {
                if ((cardTopRank[i].solution)[0].mRank < arithmetic_average) {
                    cardTopRank[i].point++;
                }
            }
        }
        if (revolution == true) {
            for (var i = 0; i < cardTopRank.length; i++) {
                if ((cardTopRank[i].solution)[0].mRank > arithmetic_average) {
                    cardTopRank[i].point++;
                }
            }
        }
    }
    else {
        for (var i = 0; i < useSolution.length; i++) {
            cardTopRank.push(new check(0, useSolution[i]));
        }
    }
    var checkmax = [];
    for (var i = 0; i < cardTopRank.length; i++) {
        checkmax[i] = cardTopRank[i].point;
    }
    checkmax.sort(function (a, b) {
        return b - a
    });
    var solutionFinal = [];
    if (cardLock.length > 0) {
        for (var i = 0; i < cardTopRank.length; i++) {
            if (cardTopRank[i].point == checkmax[0] && checkmax[0] > -2) {
                solutionFinal.push(cardTopRank[i].solution);
            }
        }
    }
    else {
        solutionFinal = useSolution;
    }
    return solutionFinal;
}
/*
 *
 *   @function: get min solution
 *
 * */
var fn_minSolution = function (mySolutions) {
    var rank = aiutils.Card_Joker;
    var index = 0;
    var ret = [];

    for (var i = 0; i < mySolutions.length; i++) {
        if (mySolutions[i][0].mRank < rank) {
                rank = (mySolutions[i])[0].mRank;
                index = i;
        }
    }
    ret = (mySolutions[index]);
    return ret;
}
/*
 *
 *  Check present solution ( Squence or Pair )
 *
 * */

var fn_checkPresent = function (solutions, cardsTable, cardLock) {
    var cArrCard = [];                  // cArrCard == Check Array Cards
    var ret = 0;

    var cRank = solutions[0].mRank + 1; //cRank == Check Rank Number
    if (solutions.length == 0) {
        solutions = cardLock;
    }
    for (var i = cRank; i < cardsTable.length; i++) {
            for (var j = 0; j < aiutils.Card_Color.j; j++) {
                if (cardsTable[i][j] == true) {
                    var Card = {};
                    Card.mRank = i;
                    Card.mColor = j;
                    cArrCard.push(Card);
                }
            }
    }

    if (aiutils.typeDealing(solutions) == aiutils.DealType.Sequ) {
        var cArrSequence = DfgRule.getAllSequence(cArrCard)
        for (var i = 0; i < cArrSequence.length; i++) {
            if (cArrSequence[i].length == solutions.length) {
                ret++;
            }
        }
    }
    else {
        var cArrPair = DfgRule.getAllPair(cArrCard)
            for (var i = 0; i < cArrPair.length; i++) {
                if (cArrPair[i].length == solutions.length && cArrPair[i][0].mColor == solutions[0].mColor) {
                    ret++;
                }
            }

    }
    return ret;
}
/*
 *
 *   @function: Decided
 *
 * */

var fn_decided = function (myCard, cardLock, mySolutions, isLockingHand, remainCard, minLengthCard, cardsTable) {
    if (cardLock.length == 0) {
        var minCard = [];
            for (var i = 0; i < myCard.length; i++) {
                if (myCard[i].deal == false) {
                    minCard = myCard[i];
                    break;
                }
            }
        var ret = 0;
        var index = 0;
        for (var i = 0; i < mySolutions.length; i++) {
            if (setutils.set_in(minCard, mySolutions[i], function (a, b) {
                    return (a.mRank == b.mRank && a.mColor == b.mColor);
                }) == true && mySolutions[i].length > ret) {
                ret = mySolutions[i].length;
                index = i
            }
        }
        return mySolutions[index];
    }
    else {
        var maxCard = card_Second;
        var ret = [];
        var tSolution = [];
        if (remainCard > warningLine && minLengthCard > warningLine) {
            for (var i = 0; i < mySolutions.length; i++) {
                var ret = 0;
                for (var j = 0; j < mySolutions[i].length; j++) {
                    if (mySolutions[i][j].mRank == maxCard) {
                        ret++;
                    }
                }
                if (ret == 0) {
                    tSolution.push(mySolutions[i])
                }
                else {

                }
            }
        }
        else {
            tSolution = mySolutions;
        }
        if (tSolution.length == 0) {
            return tSolution;
        }
        if (remainCard < 4) {
            var rank = Infinity;
            var number = 0;
            for (var i = 0; i < tSolution.length; i++) {
                if (fn_checkPresent(tSolution[i], cardsTable, isLockingHand, cardLock) < rank) {
                    number = i;
                    rank = fn_checkPresent(tSolution[i], cardsTable, isLockingHand, cardLock);
                }
            }
            return tSolution[number];
        }
            ret = fn_minSolution(tSolution);
            return ret;


    }
}
/*
 *
 *   Number of RemainCard
 *
 * */
var fn_remainCard = function (myCards) {
    var ret = 0;
    for (var i = 0; i < myCards.length; i++) {
        if (myCards[i].deal == false) {
            ret++;
        }
    }
    return ret;
}



// Test checkDominantSolution
//var cardsT = [];
//for(var i = 0; i < aiutils.Card_Joker; i++){
//    cardsT[i] = [];
//    for(var j = 0; j < aiutils.Card_Color.j; j++){
//        cardsT[i][j] = false;
//    }
//}
//cardsT[aiutils.Card_Joker] = true;
//cardsT[4][0] = true;
//cardsT[6][0] = true;
//cardsT[7][0] = true;
//cardsT[12][3] = true;
//cardsT[9][3] = true;
//cardsT[10][3] = true;

//var solu = [{mRank: 7, mColor: 1}, {mRank: 7, mColor: 2}];
//var solu = [{mRank: 5, mColor: 1}, {mRank: 6, mColor: 1}, {mRank: 7, mColor: 1}];
//var solu = [{mRank: 9, mColor: 1}, {mRank: 10, mColor: 1}, {mRank: 11, mColor: 1}];
//var myCards = [{mRank: 4, mColor: 0}, {mRank: 16, mColor: 4}]

//var isDominant = checkDominantSolution(solu, cardsT, true);

//logger.info("Dominant Result: " + isDominant);

//logger.info(getOtherCardsTable(myCards, cardsT));

